﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Imageo.bintje;
using System.Web.UI;
using log4net;
using System.Collections.Specialized;

namespace Imageo
{
    /// <summary>
    /// Service helper isolate backend changes and handles error code converting them to exceptions
    /// </summary>
    public class ServiceHelper
    {
        private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        /// <summary>
        /// This methods handles the Bintje status messages that come embedded in the server responses 
        /// </summary>
        /// <typeparam name="T">Response type</typeparam>
        /// <param name="response">Response value</param>
        /// <returns>The response</returns>
        public static T HandleBintjeErrors<T>(Page page, T response)
        {
            if (response == null)
            {
                if (log.IsErrorEnabled)
                {
                    log.Error("Response object was null");
                }
            }

            serviceResponse sr = response as serviceResponse;
            if (sr == null) return response;

            log.Error("Response Status: " + sr.status);
            switch (sr.status)
            {
                case "MESSAGE_INCORRECT_INPUT":
                    break;
                case "STATUS_ERROR_INVALID_INPUT":
                    break;
                case "STATUS_ERROR_RESOURCE_NOT_FOUND":
                    break;

                case "SESSION_TIMEOUT":
                case "SESSION TIMEOUT":
                    if (page != null)
                        page.Response.Redirect("~/UI/ErrorSessionTimeout.aspx");
                    break;
                case "MESSAGE_NO_SESSION":
                case "STATUS_ERROR_UNAUTHORIZED":
                    // Force the user to login again
                    // we should probably redirect to login window or something similar.
                    break;

                case "STATUS_ERROR":
                    if (sr.message == "SESSION TIMEOUT" || sr.message == "Session not found or expired")
                    {
                        if (page != null)
                            page.Response.Redirect("~/UI/ErrorSessionTimeout.aspx");
                        break;
                    }
                    throw new Exception(sr.message);

                case "STATUS_ERROR_UNSPECIFIED":
                    // Log the error and move to some error window
                    break;

                case "STATUS_NORMAL":
                case "NORMAL":
                    // everything went ok
                    break;

                case ": user already exists, choose another loginname.":
                    throw new Exception("This email address is already registered");

                default:
                    throw new Exception("Unknown status response from bintje");
            }

            return response;
        }
    }

    /// <summary>
    /// trail wrapper
    /// </summary>
    public class trailBox
    {
        private int id;
        public int Id
        {
            get { return id; }
            set { id = value; }
        }

        private string title;
        public string Title
        {
            get { return title; }
            set { title = value; }
        }

        private int proUserId;
        public int ProUserId
        {
            get { return proUserId; }
            set { proUserId = value; }
        }

        private int imageId;
        public int ImageId
        {
            get { return imageId; }
            set { imageId = value; }
        }

        private string imageUrl;
        public string ImageUrl
        {
            get { return imageUrl; }
            set { imageUrl = value; }
        }

        private string description;
        public string Description
        {
            get { return description; }
            set { description = value; }
        }

        private string city;
        public string City
        {
            get { return city; }
            set { city = value; }
        }

        private string country;
        public string Country
        {
            get { return country; }
            set { country = value; }
        }

        private string length;
        public string Length
        {
            get { return length; }
            set { length = value; }
        }

        private string layers;
        public string Layers
        {
            get { return layers; }
            set { layers = value; }
        }

        private string addedBy;
        public string AddedBy
        {
            get { return addedBy; }
            set { addedBy = value; }
        }

        private string addedOn;
        public string AddedOn
        {
            get { return addedOn; }
            set { addedOn = value; }
        }

        private string waypoints;
        public string Waypoints
        {
            get { return waypoints; }
            set { waypoints = value; }
        }

        private string visits;
        public string Visits
        {
            get { return visits; }
            set { visits = value; }
        }

        private string openTrailUrl;
        public string OpenTrailUrl
        {
            get { return openTrailUrl; }
            set { openTrailUrl = value; }
        }

        private string searchSimilarTrailUrl;
        public string SearchSimilarTrailUrl
        {
            get { return searchSimilarTrailUrl; }
            set { searchSimilarTrailUrl = value; }
        }

        private string displaySimilarTrailOption;
        public string DisplaySimilarTrailOption
        {
            get { return displaySimilarTrailOption; }
            set { displaySimilarTrailOption = value; }
        }

        private string searchSimilarImageUrl;
        public string SearchSimilarImageUrl
        {
            get { return searchSimilarImageUrl; }
            set { searchSimilarImageUrl = value; }
        }

        private string displaySimilarImageOption;
        public string DisplaySimilarImageOption
        {
            get { return displaySimilarImageOption; }
            set { displaySimilarImageOption = value; }
        }

        private string latitude;
        public string Latitude
        {
            get { return latitude; }
            set { latitude = value; }
        }

        private string longitude;
        public string Longitude
        {
            get { return longitude; }
            set { longitude = value; }
        }

        static string urlPhotoNotAvailable;
        public static void initPaths(TemplateControl tmpTemplateControl)
        {
            urlPhotoNotAvailable = tmpTemplateControl.ResolveClientUrl(@"..\images\photo_not_available.jpg");
        }

        public trailBox(bintje.trailWrapper tw, int proUserId)
        {
            ProUserId = proUserId;
            City = tw.city;
            Country = tw.country;
            Length = tw.length.ToString("0.00") + "km";
            AddedOn=tw.created.ToShortDateString();
            AddedBy=tw.usernick;
            Visits=tw.visited.ToString();
            Waypoints = tw.numberOfWaypoints.ToString();

            SearchSimilarTrailUrl = "";
            DisplaySimilarTrailOption = "display: none;";
            SearchSimilarImageUrl = "";
            DisplaySimilarImageOption = "display: none;";

            if (proUserId > 0)
            {
                OpenTrailUrl = "?trailid=" + tw.id + "&prouserid=" + proUserId.ToString();
            }
            else
            {
                OpenTrailUrl = "?trailid=" + tw.id;
            }

            ImageUrl = urlPhotoNotAvailable;
            if (tw.imageUrl != null)
            {
                ImageUrl = tw.imageUrl.Replace("type=image", "type=thumb");
                Uri tmpUri = new Uri(tw.imageUrl.ToLower());
                NameValueCollection nvc = HttpUtility.ParseQueryString(tmpUri.Query);

                string imageid = nvc["id"];
                if (imageid != null)
                {
                    if (proUserId > 0)
                    {
                        SearchSimilarImageUrl = "?imageId=" + imageid + "&prouserid="+proUserId.ToString();
                        DisplaySimilarImageOption = "";
                        SearchSimilarTrailUrl = "?trailid=" + tw.id + "&imageId=" + imageid + "&prouserid=" + proUserId.ToString();
                        DisplaySimilarTrailOption = "";
                    }
                    else
                    {
                        SearchSimilarImageUrl = "?imageId=" + imageid;
                        DisplaySimilarImageOption = "";
                        SearchSimilarTrailUrl = "?trailid=" + tw.id + "&imageId=" + imageid;
                        DisplaySimilarTrailOption = "";
                    }
                }
            }

            Id = tw.id;
            Title = tw.title;

            const int descriptionLimit = 90;
            Description = "";

            if (tw.description != null)
            {
                if (tw.description.Length < descriptionLimit)
                {
                    Description = tw.description;
                }
                else
                {
                    Description = tw.description.Substring(0, descriptionLimit - 3) + "...";
                }
            }

            if (string.IsNullOrEmpty(Description)) Description = "No description";
            if (string.IsNullOrEmpty(Title)) Title = "No title";
        }

        public trailBox(imageWrapper iw, int proUserId)
        {
            ProUserId = proUserId;
            Latitude=iw.latitude;
            Longitude=iw.longitude;
            Id = iw.trailId;

            SearchSimilarTrailUrl = "?trailid=" + Id + "&lat=" + Latitude + "&lon=" + Longitude;
            DisplaySimilarTrailOption = "";

                        if (proUserId > 0)
            {
                OpenTrailUrl = "?trailid=" + Id + "&prouserid=" + proUserId.ToString();
            }
            else
            {
                OpenTrailUrl = "?trailid=" + Id;
            }

            SearchSimilarImageUrl = "";
            DisplaySimilarImageOption = "display: none;";
            ImageUrl = urlPhotoNotAvailable;
            if (iw.url != null)
            {
                ImageUrl = iw.url.Replace("type=image", "type=thumb");
                Uri tmpUri = new Uri(iw.url.ToLower());
                NameValueCollection nvc = HttpUtility.ParseQueryString(tmpUri.Query);

                string imageid = iw.id.ToString();
                if (imageid != null)
                {
                    if (proUserId > 0)
                    {
                        SearchSimilarImageUrl = "?imageId=" + imageid + "&prouserid=" + proUserId.ToString();
                        DisplaySimilarImageOption = "";
                        SearchSimilarTrailUrl = "?trailid=" + Id + "&imageId=" + imageid + "&prouserid=" + proUserId.ToString();
                        DisplaySimilarTrailOption = "";
                    }
                    else
                    {
                        SearchSimilarImageUrl = "?imageId=" + imageid;
                        DisplaySimilarImageOption = "";
                        SearchSimilarTrailUrl = "?trailid=" + Id + "&imageId=" + imageid;
                        DisplaySimilarTrailOption = "";
                    }
                }
            }

        }
    }

    /// <summary>
    /// Data Source Object - provide paging/filtering/etc
    /// </summary>
    public class TrailDataSourceObject
    {
        static int lastSize;

        #region SELECT TRAILS
        public static List<trailBox> SelectTrails(bintje.imageoSession currentSession, string searchString, string imageIdStr, string trailIdStr, string proUserIdStr, string userIdStr, string latitudeStr, string longitudeStr, string sortField, string sortDirection, int startRowIndex, int maximumRows)
        {
            List<trailBox> result = new List<trailBox>();

            ServiceAPI service = new ServiceAPI();
            trailListResponse trailsResponse;
            searchRequest trailsRequest = new searchRequest();

            trailsRequest.session = currentSession;
            trailsRequest.sortingField = sortField;
            trailsRequest.descending = (sortDirection == "descending");

            int proUserId;
            if (!int.TryParse(proUserIdStr, out proUserId))
                proUserId = 0;

            if (proUserId > 0)
            {
                trailsRequest.professionalUser = proUserId;
                trailsRequest.searchWithinUser = true;
            }

            int userId;
            if (!int.TryParse(userIdStr, out userId))
                userId = 0;

            if (userId > 0)
            {
                trailsRequest.userid = userId;
                trailsRequest.searchType = "user";

                if (currentSession != null )
                    if (currentSession.userId == userId)
                    {
                        trailsRequest.searchType = "mytrails";
                    }
            }

            int trailId;
            int imageId;
            double tmpLatitude;
            double tmpLongitude;

            if (!int.TryParse(trailIdStr, out trailId))
                trailId = 0;
            if (!int.TryParse(imageIdStr, out imageId))
                imageId = 0;
            if (!double.TryParse(latitudeStr, out tmpLatitude))
                tmpLatitude = 0;
            if (!double.TryParse(longitudeStr, out tmpLongitude))
                tmpLongitude = 0;
            trailsRequest.latitude = tmpLatitude;
            trailsRequest.longitude = tmpLongitude;

            if (trailId > 0 && imageId>0)
            {
                similarImageRequest tempRequest=new similarImageRequest();
                tempRequest.imageId=imageId;
                tempRequest.innerRadius=0;
                tempRequest.outerRadius=100000;
                tempRequest.maximumNumber=20;
                tempRequest.trailstoexclude = null;
                if (proUserId > 0)
                {
                    tempRequest.userId = proUserId;
                }
                tempRequest.session = currentSession;

                // Special case here
                trailsResponse = ServiceHelper.HandleBintjeErrors(null, service.getSimilarTrails((tempRequest)));

                for (int i = startRowIndex; i < startRowIndex + maximumRows && i < trailsResponse.trailList.Length; i++)
                {
                    result.Add(new trailBox(trailsResponse.trailList[i], proUserId));
                }

                lastSize = trailsResponse.totalTrails;
                return result;

//                trailsRequest.searchType = "geolocation";
//                if (trailsRequest.sortingField == "")
//                {
//                    trailsRequest.sortingField = "distance";
//                    trailsRequest.descending = false;
//                }
//                trailsRequest.radius = 5000;
            }

            if (!string.IsNullOrEmpty(searchString))
            {
                trailsRequest.searchType = "string";
                trailsRequest.searchString = searchString;
            }

            if (string.IsNullOrEmpty(trailsRequest.searchType))
                trailsRequest.searchType = "all";

            trailsRequest.numberOfTrails = maximumRows + 1;
            trailsRequest.firstCount = startRowIndex;
            trailsRequest.session = currentSession;

            // hack until erna fixes the problem
//            if (trailsRequest.firstCount + trailsRequest.numberOfTrails > lastSize && lastSize > 0)
//            {
//                trailsRequest.numberOfTrails = lastSize - trailsRequest.firstCount + 1;
//            }
            trailsRequest.numberOfTrails = maximumRows;

            trailsResponse = ServiceHelper.HandleBintjeErrors(null, service.getTrails(trailsRequest));
            lastSize = 0;

            if (trailsResponse!=null)
            {
                if (trailsResponse.trailList != null)
                {
                    foreach (trailWrapper t in trailsResponse.trailList)
                        result.Add(new trailBox(t, proUserId));
                    lastSize = trailsResponse.totalTrails;
                }
            }

            return result;
        }

        public static int SelectTrailsCount(bintje.imageoSession currentSession, string searchString, string imageIdStr, string trailIdStr, string proUserIdStr, string userIdStr, string latitudeStr, string longitudeStr, string sortField, string sortDirection, int startRowIndex, int maximumRows)
        {
            return lastSize;
        }
        
        #endregion

        #region SIMILAR IMAGES
        public static List<trailBox> SelectSimilarImages(bintje.imageoSession currentSession, string imageIdStr, string proUserIdStr, int startRowIndex, int maximumRows)
        {
            List<trailBox> result = new List<trailBox>();

            ServiceAPI service = new ServiceAPI();
            searchRequest trailsRequest = new searchRequest();

            trailsRequest.session = currentSession;

            int proUserId;
            if (!int.TryParse(proUserIdStr, out proUserId))
                proUserId = 0;

            if (proUserId > 0)
            {
                trailsRequest.professionalUser = proUserId;
                trailsRequest.searchWithinUser = true;
            }

            int imageId;
            if (!int.TryParse(imageIdStr, out imageId))
                imageId = 0;

            if (imageId > 0)
            {
                similarImageRequest sireq = new similarImageRequest();
                similarImageResponse imgResponse;

                sireq.imageId = imageId;
                sireq.innerRadius = 0;
                sireq.outerRadius = 1000000;
                sireq.maximumNumber = 10;
                sireq.trailstoexclude = null;
                if (proUserId > 0)
                {
                    sireq.userId = proUserId;
                }
                sireq.session = currentSession;
                imgResponse = ServiceHelper.HandleBintjeErrors(null, service.getSimilarImages(sireq));

                // This is a quick fix for paging
                int i = 0;
                while (i < maximumRows && i+startRowIndex < imgResponse.images.Length)
                {
                    result.Add(new trailBox(imgResponse.images[i + startRowIndex], proUserId));
                    i++;
                }
// All
//                foreach (imageWrapper iw in imgResponse.images)
//                    result.Add(new trailBox(iw));
            }

            return result;
        }

        public static int SelectSimilarImagesCount(bintje.imageoSession currentSession, string imageIdStr, string proUserIdStr, int startRowIndex, int maximumRows)
        {
            return 10;
        }
        #endregion
    }

}
